/*
 *	Copyright (c) 2013, Yulong Information Technologies
 *	All rights reserved.
 *  
 *  @Project: Db
 *  @author: Robot
 *	@email: feng88724@126.com
 */
package com.example.db.core;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import com.example.db.core.annotation.PK;
import com.example.db.core.annotation.Table;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

/**
 * @author Robot
 * @weibo http://weibo.com/feng88724
 * @date Apr 12, 2013	
 */
public class DBKit {
	private static final String TAG = DBKit.class.getSimpleName();

	/**
	 * 获取数据表名称
	 * 有注解就用注解, 无注解就用类名
	 * @param clazz
	 * @return
	 */
	public static String getTableName(Class<?> clazz) {
		Table table = clazz.getAnnotation(Table.class);
		if(table == null || table.name().trim().length() == 0 ) {
			return clazz.getSimpleName();
		}
		return table.name();
	}
	
	/**
	 * 获取主键名
	 * @return
	 */
	public static String getPrimaryKeyName(Class<?> clazz) {
		String name = null;
		for (Field column : clazz.getClass().getDeclaredFields()) {
			//判断是否主键
			if(column.isAnnotationPresent(PK.class)){
				name = column.getName();
				break;
			}
		}
		return name;
	}
	
	/**
	 * 获取主键值
	 * @return
	 */
	public static Object getPrimaryKeyValue(Class<?> clazz) {
		Object value = null;
		for (Field column : clazz.getClass().getDeclaredFields()) {
			//判断是否主键
			if(column.isAnnotationPresent(PK.class)) {
				try {
					value = column.get(clazz);
				} catch (Exception e) {
					Log.e(TAG, "", e);
				}
				break;
			}
		}
		return value;
	}
	
	/**
	 * 把列的值，转换成对象里属性的值
	 * @param t
	 * @param c
	 */
	public static <M> void columnToField(M t, Cursor c) {
		Field[] field = t.getClass().getDeclaredFields();
		for (int i = 0; i < field.length; i++) {
			int columnIndex = c.getColumnIndex(field[i].getName());
			//如果为-1，表示不存在此列
			if(columnIndex == -1){
				continue;
			}

			Class<?>  classz = field[i].getType();
			if(!field[i].isAccessible())
				field[i].setAccessible(true);

			try {
				if(classz == Integer.TYPE) {   //int
					field[i].set(t, c.getInt(columnIndex));
				}else if(classz == String.class){   //String
					field[i].set(t, c.getString(columnIndex));
				}else if(classz == Long.TYPE){   //long
					field[i].set(t, c.getLong(columnIndex));
				}else if(classz == byte[].class){   //byte
					field[i].set(t, c.getBlob(columnIndex));
				}else if(classz == Float.TYPE){   //float
					field[i].set(t, c.getFloat(columnIndex));
				}else if(classz == Double.TYPE){   //double
					field[i].set(t, c.getDouble(columnIndex));
				}else if(classz == Short.TYPE){   //short
					field[i].set(t, c.getShort(columnIndex));
				}
			} catch (Exception e) {
				Log.e(TAG, e.getMessage());
			}
		}
	}
	
	private static SQLiteDatabase getSQLiteDatabase() {
		return DBConfig.getDatabase();
	}
	
	//----------------------------------------------------------------------------------------
	// 新增
	//----------------------------------------------------------------------------------------
	
	/**
	 * 保存
	 * @param <M>
	 * @param clazz
	 * @return
	 */
	public static long save(Object object) {
		long flag = -1;
		Field []fields = object.getClass().getDeclaredFields();
		ContentValues values = new ContentValues(fields.length);
		try {
			StringBuilder sb = new StringBuilder();
			for(Field field : fields) {
				if(sb.length() == 0)
					sb.append(",");
				sb.append(String.format("%s(%s", field.getName(),field.getType().getSimpleName()));
				//if(field.isAnnotationPresent(PK.class)&&field.isAnnotationPresent(GeneratedId.class))
				if(field.isAnnotationPresent(PK.class))
					continue;
				if(!field.isAccessible())
					field.setAccessible(true);
				values.put(field.getName(), String.valueOf(field.get(object)));
			}
			Log.d(TAG, "fields: " + sb.toString());
		} catch (IllegalAccessException e) {
			Log.e(TAG, e.getMessage());
		}

		flag = getSQLiteDatabase().insert(getTableName(object.getClass()), null, values);

		return flag;
	}
	
	//----------------------------------------------------------------------------------------
	// 查询
	//----------------------------------------------------------------------------------------
	
	private static Cursor select(String sql, String[] bindArgs) {
		return getSQLiteDatabase().rawQuery(sql, bindArgs);
	}
	
	/**
	 * 查询, 只返回一条满足条件的记录
	 * @param sql
	 * @param bindArgs
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <M> M find(Class<M> clazz, String sql, String[] bindArgs){
		Cursor cursor = select(sql, bindArgs);
		M t = null;
		if(cursor.moveToFirst()){
			try {
				t = (M)clazz.getClass().newInstance();

				//把列的值，转换成对象里属性的值
				columnToField(t, cursor);
			} catch(Exception e) {
				Log.e(TAG, "", e);
			}
		}
		cursor.close();
		return t;
	}
	
	/**
	 * 查询, 返回记录集
	 * @param sql			SQL语句
	 * @param bindArgs		
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <M> List<M> findList(Class<M> m, String sql, String[] bindArgs) {
		Cursor cursor = select(sql, bindArgs);
		List<M> list = new ArrayList<M>(cursor.getCount());
		M t = null;
		while (cursor.moveToNext()) {
			try {
				t = (M)m.getClass().newInstance();

				//把列的值，转换成对象里属性的值
				columnToField(t, cursor);

				list.add(t);
			} catch(Exception e) {
				Log.e(TAG, e.getMessage());
			}
		}
		cursor.close();
		return list;
	}
	
	/**
	 * 查询, 所有记录
	 * @param <M>	类型
	 * @param m
	 * @return
	 */
	public static <M> List<M> findAll(Class<M> m) {
		return findList(m, "select * from " + getTableName(m), null);
	}
	
	//----------------------------------------------------------------------------------------
	// 删除
	//----------------------------------------------------------------------------------------
	
	/**
	 * 根据主键删除
	 * @return
	 */
	public static boolean delete(Object object) {
		return delete(object.getClass(), getPrimaryKeyName(object.getClass()) + " = ?", new String[] {String.valueOf(getPrimaryKeyValue(object.getClass()))});
	}
	
	/**
	 * 根据其他条件删除
	 * @param clazz
	 * @param whereClause
	 * @param whereArgs
	 * @return
	 */
	public static boolean delete(Class<?> clazz, String whereClause, String[] whereArgs) {
		return delete(getTableName(clazz),whereClause, whereArgs);
	}
	
	/**
	 * 根据其他条件删除
	 * @param whereClause
	 * @param whereArgs
	 * @return
	 */
	public static boolean delete(String table, String whereClause, String[] whereArgs) {
		int val = getSQLiteDatabase().delete(table, whereClause, whereArgs);
		if(val > 0) {
			return true;
		}
		return false;
	}
	
	//----------------------------------------------------------------------------------------
	// 更新
	//----------------------------------------------------------------------------------------
	
	/**
	 * 更新
	 * 根据主键来更新, 必须包含主键及主键值
	 * @param object
	 * @return
	 */
	public static boolean update(Object object) {
		Field []fields = object.getClass().getDeclaredFields();
		ContentValues values = new ContentValues(fields.length);
		String keyName = null;
		Object keyValue = null;
		try {
			for(Field field : fields) {
				if(field.isAnnotationPresent(PK.class)){
					keyName = field.getName();
					keyValue = field.get(object);
				}

				if(!field.isAccessible())
					field.setAccessible(true);
				values.put(field.getName(), String.valueOf(field.get(object)));
			}
		} catch (IllegalAccessException e) {
			Log.e(TAG, e.getMessage());
		}
		
		if(keyName == null)
			throw new RuntimeException("The Primary Key cannot be null.");
		
		if(keyValue == null)
			throw new RuntimeException("The Primary Key's Value cannot be null.");

		int flag = update(getTableName(object.getClass()), values, keyName + " = ?", new String[] {String.valueOf(keyValue)});
		if(flag >= 0) {
			Log.d(TAG, "Affect rows number : " + flag);
			return true;
		}
		return false;
	}
	
	/**
	 * 更新
	 * @param table				表名
	 * @param values			数据
	 * @param whereClause		条件
	 * @param whereArgs			条件值
	 */
	public static int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
		return getSQLiteDatabase().update(table, values, whereClause, whereArgs);
	}
}